package com.kh.tool.mapvalidator;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.util.StringUtils;
import org.springframework.validation.AbstractBindingResult;

import java.util.*;

public class CustomMapBindingResult extends AbstractBindingResult {
    private final Map<?, ?> target;
    public static final String REGEX = "\\(\\d+\\)";
    private Properties properties = new Properties();
    private LinkedHashMap<String, List<String>> columns;

    public CustomMapBindingResult(String objectName, Map<?, ?> target) {
        super(objectName);
        this.target = target;
        net.sf.json.JSONObject jsonObject = net.sf.json.JSONObject.fromObject(target);
        parseJSONObjectToProperties(jsonObject,properties,"");
        columns = new LinkedHashMap<>();
        addColumnConflict(properties.keySet());
    }

    private void addColumnConflict(Set<Object> conflictingColumn) {
        for (Object keyObj : conflictingColumn) {
            String key = keyObj.toString();
            String proName = key.replaceAll(REGEX, "");
            List<String> list = columns.computeIfAbsent(proName, k -> new ArrayList<>());
            list.add(key);
        }
    }

    @Override
    public Object getTarget() {
        return this.target;
    }

    @Override
    protected Object getActualFieldValue(String field) {
        return this.properties.get(field);
    }

    public Properties getProperties() {
        return properties;
    }

    public LinkedHashMap<String, List<String>> getColumns() {
        return columns;
    }

    /**
     * 将JSONObject转换成Properties键值对
     * @param jsonObject
     * @param properties
     * @param propertyPrefix
     */
    private static void parseJSONObjectToProperties(net.sf.json.JSONObject jsonObject, Properties properties, String propertyPrefix) {
        Iterator<String> it = jsonObject.keySet().iterator();
        String prefixCopy = propertyPrefix;
        while (it.hasNext()) {
            final String key = it.next();
            final Object value = jsonObject.get(key);
            if (value instanceof net.sf.json.JSONObject) {
                if (StringUtils.hasText(propertyPrefix)) {
                    prefixCopy = prefixCopy + key + ".";
                } else {
                    prefixCopy = key+".";
                }
                parseJSONObjectToProperties((net.sf.json.JSONObject) value,properties,prefixCopy);
            }
            else if (value instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray) value;
                for (int i = 0; i < jsonArray.size(); i++) {
                    JSONObject obj =  (JSONObject) jsonArray.get(i);
                    if (StringUtils.hasText(propertyPrefix)) {
                        prefixCopy = prefixCopy + key + "(" + i + ")"  + ".";
                    } else {
                        prefixCopy = key + "(" + i + ")" + ".";
                    }
                    parseJSONObjectToProperties(obj,properties,prefixCopy);

                    prefixCopy = propertyPrefix; //递归调用中的清理现场功能 此处在整个递归调用过程中必不可少
                }
            }
            properties.put(propertyPrefix + key,value);
        }
    }
    /*** 记录递归推导过程
     *
     * pjt()            propertyPrefix = ""                                           prefixCopy = "applyList(0)."
     *
     * pjt(goodList)    propertyPrefix = "applyList(0)."                              prefixCopy = "applyList(0).goodList(0)."
     *
     * pjt(content)    propertyPrefix = "applyList(0).goodList(0)."                   prefixCopy = "applyList(0).goodList(0).content"
     *
     * pjt(content)    propertyPrefix = "applyList(0).goodList(0).content"            prefixCopy = "applyList(0).goodList(0).content"
     *
     */

    /**
     * * pjt() prefix = ""
     *      *
     *      * pjt(obj)    propertyPrefix = ""            prefixCopy = "obj."
     *      *
     *      * pjt(user)  propertyPrefix = "obj.user"     prefixCopy = "obj.user.un"
     *      *
     *      * pjt(un)   propertyPrefix = "obj.user.un"   prefixCopy = "obj.user.un" [p.put(obj.user.un,"")]
     */
}
